{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 动手实现胶囊网络\n",
    "\n",
    "## 前言\n",
    "\n",
    "2017年，Hinton团队提出胶囊网络，首次将标量型网络扩展到矢量。本着learning by doing的态度，我尝试对原论文进行复现，因此这里不会对其原论文原理和思想有太多解释。尽可能保证工程性和完整性，并在实现过程中不断总结和反思。实现过程中也许会有一些bug，欢迎交流和提交issue~\n",
    "\n",
    "**Author**: QiangZiBro   \n",
    "**Github**: https://github/QiangZiBro\n",
    "\n",
    "\n",
    "## 1.1 引入必备的包\n",
    "本文依赖第三方框架pytorch，实验使用1.2，基本来说各个版本都可以用。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "import torchvision\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "from torchvision import transforms\n",
    "from torchvision.utils import save_image"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1.2 超参数定义"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Device configuration\n",
    "device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n",
    "\n",
    "# Hyper-parameters\n",
    "num_epochs = 5\n",
    "batch_size = 64\n",
    "learning_rate = 1e-3"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1.3 数据加载"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {},
   "outputs": [],
   "source": [
    "# MNIST dataset\n",
    "root=\"/home/qiangzibro/2TB1/\"\n",
    "train_dataset = torchvision.datasets.MNIST(root=root,\n",
    "                                           train=True, \n",
    "                                           transform=transforms.ToTensor(),\n",
    "                                           download=True)\n",
    "\n",
    "test_dataset = torchvision.datasets.MNIST(root=root,\n",
    "                                          train=False, \n",
    "                                          transform=transforms.ToTensor())\n",
    "\n",
    "# Data loader\n",
    "train_loader = torch.utils.data.DataLoader(dataset=train_dataset,\n",
    "                                           batch_size=batch_size, \n",
    "                                           shuffle=True)\n",
    "\n",
    "test_loader = torch.utils.data.DataLoader(dataset=test_dataset,\n",
    "                                          batch_size=batch_size, \n",
    "                                          shuffle=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "label is 2\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "def show_img(data_tuple):\n",
    "    img, label = data_tuple\n",
    "    img = img.squeeze()\n",
    "    plt.imshow(img)\n",
    "    print(f\"label is {label}\")\n",
    "    \n",
    "show_img(test_dataset[1])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1.4 胶囊网络的压缩函数与动态路由算法\n",
    "胶囊网络由三层组成：卷积层，初级胶囊层，卷积胶囊层，其中卷积胶囊层使用了动态路由算法。我们来一一实现这些功能。\n",
    "首先实现两个函数，压缩函数与动态路由函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([1, 10, 16])"
      ]
     },
     "execution_count": 60,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def squash(x):\n",
    "    \"\"\"\n",
    "    Args:\n",
    "        x: (B, 10, 16)\n",
    "    Return:\n",
    "        squashed x (B, 10, 16)\n",
    "    \"\"\"\n",
    "    L = torch.norm(x, dim=2, keepdim=True) #(B, 10, 1)\n",
    "    L_square = L**2 #(B, 10, 1)\n",
    "    c = (L_square)/(1+L_square)/L #(B, 10, 1)\n",
    "    \n",
    "    s = c*x #(B, 10, 16)\n",
    "    s[s==np.nan] = 0\n",
    "    return s\n",
    "\n",
    "x = torch.rand(1,10,16)\n",
    "squash(x).shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "动态路由算法相当于一个聚类过程，将底层的若干个向量以迭代的路由方法，选取若干具有代表性的胶囊。\n",
    "- 输入 (B, 10, 32x6x6, 16)\n",
    "- 输出 (B, 10, 16)\n",
    "\n",
    "要注意的细节\n",
    "- b的维度是多少？ b是有batchsize的，我最开是设置的是没有batchsize，效果不太好。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([1, 10, 16])"
      ]
     },
     "execution_count": 61,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def dynamic_routing(x, iterations=3):\n",
    "    \"\"\"\n",
    "    Args:\n",
    "        x: u_hat,  (B, 10, 32x6x6, 16, 1)\n",
    "        \n",
    "    Return:\n",
    "        v: next layer output (B, 10, 16)\n",
    "    \"\"\"\n",
    "    N = 32*6*6 # previous layer\n",
    "    N1 = 10 # next layer\n",
    "    B = x.shape[0]\n",
    "    \n",
    "    b = torch.zeros(B,N1,N,1, 1).to(x.device)\n",
    "    for _ in range(iterations):        \n",
    "        # probability of each vector to be distributed is 1\n",
    "        # (B,10,32*6*6,1, 1)\n",
    "        c = F.softmax(b, dim=1)  \n",
    " \n",
    "        # (B,10,16)\n",
    "        s = torch.sum(x.matmul(c), dim=2).squeeze(-1)\n",
    "     \n",
    "        # (B,10,16)\n",
    "        v = squash(s)\n",
    "\n",
    "        # (B,10,32*6*6,1,1)\n",
    "        b = b + v[:,:,None,None,:].matmul(x)\n",
    "\n",
    "        \n",
    "    return v\n",
    "\n",
    "x = torch.rand(1,10,32*6*6,16, 1)\n",
    "dynamic_routing(x).shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1.5 初级胶囊层\n",
    "在实现初级胶囊层时，我们要了解一些细节，比如\n",
    "- 怎样表示一个胶囊？ 每个像素点上一个1x8的向量\n",
    "- 怎样计算出初级胶囊？使用32组卷积核，每组输出8个通道\n",
    "- 怎样在程序里存这些胶囊？我的做法是将所有的胶囊放在一列，换句话说，放在一个`(B, 32*6*6, 8)`的矩阵里面"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {},
   "outputs": [],
   "source": [
    "class PrimaryCapsuleLayer(nn.Module):\n",
    "    def __init__(self):\n",
    "        super().__init__()\n",
    "        self.primary_capsule_layer = \\\n",
    "            nn.ModuleList([nn.Conv2d(256,8,9, stride=2) for _ in range(32)])\n",
    "        \n",
    "    def forward(self, x):\n",
    "        \"\"\" Produce primary capsules\n",
    "        \n",
    "        Args:\n",
    "            x: features with (B, 256, 20, 20)\n",
    "            \n",
    "        Return:\n",
    "            vectors (B, 32*6*6, 8)\n",
    "        \"\"\"\n",
    "        capsules = [conv(x) for conv in self.primary_capsule_layer]  # [[B, 8, 6, 6] * 32] \n",
    "        capsules_reshaped = [c.reshape(-1,8,6*6) for c in capsules]  # [[B, 8, 36] * 32] \n",
    "        s = torch.cat(capsules_reshaped, dim=-1).permute(0, 2, 1)  # (B, 32*6*6, 8)\n",
    "        return squash(s)\n",
    "\n",
    "    \n",
    "\n",
    "# 测试单元\n",
    "def test_for_primary_capsule_layer():\n",
    "    input = torch.rand(1,256,20,20)\n",
    "    layer = PrimaryCapsuleLayer()\n",
    "    assert layer(input).shape == (1,32*6*6, 8)\n",
    "test_for_primary_capsule_layer()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1.6 卷积胶囊层\n",
    "在实现卷积胶囊层时，我们要了解一些细节，比如\n",
    "- 高维矩阵相乘怎么进行计算？\n",
    "  比如对(B, 32x6x6, 8)大小的向量矩阵，通过权重矩阵，得到输出(B,10, 32x6x6,16)的矩阵，通过下面高维矩阵相乘方式推出$o=Wx$\n",
    "  - W `(1, 10, 32x6x6, 16, 8)`\n",
    "  - x `(B, 1,  32x6x6, 8,  1) `  \n",
    "  - o `(B, 10, 32x6x6, 16, 1)`\n",
    "  \n",
    "  上面两个矩阵相乘看起来有点复杂，怎么思考呢？多维矩阵的相乘可以看作最后两个维度作矩阵乘法，两个维度我们肯定很清楚，维度(a,b)和(b,c)两个矩阵相乘就是(a,c)。其他维度要么进行广播机制，要么不变。所以，从上面的维度，可以知道，前两个维度实行广播机制，第三个不变，最后两个维度的乘法也就是(16,8)和(8,1)的向量相乘，完成了变换。因此，就有了下面的例子\n",
    "  ```python\n",
    "    B = 1\n",
    "    x = torch.rand(B,32*6*6,8)\n",
    "    x = x[:,None,...,None]\n",
    "\n",
    "    w = torch.rand(1,10,32*6*6,16,8)\n",
    "    w.matmul(x).shape\n",
    "    # torch.Size([1, 10, 1152, 16, 1])\n",
    "    ```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "metadata": {},
   "outputs": [],
   "source": [
    "class CapsLayer(nn.Module):\n",
    "    def __init__(self,nclasses=10, out_channels_dim=16):\n",
    "        super().__init__()\n",
    "        self.W = nn.Parameter(1e-3 * torch.randn(1,nclasses,32*6*6,out_channels_dim,8))\n",
    "        \n",
    "    def forward(self, x):\n",
    "        \"\"\"Predict and routing\n",
    "        \n",
    "        Args:\n",
    "            x: Input vectors, (B, 32*6*6, 8)\n",
    "            \n",
    "        Return:\n",
    "            class capsules, (B, 10, 16)\n",
    "        \"\"\"\n",
    "        x = x[:,None,...,None]\n",
    "        u_hat = self.W.matmul(x)  # (B, 10, 32x6x6, 16, 1)\n",
    "        assert u_hat.shape[1:] == (10, 32*6*6, 16, 1)\n",
    "        class_capsules = dynamic_routing(u_hat)\n",
    "        return class_capsules\n",
    "    \n",
    "    \n",
    "def test_for_caps_layer():\n",
    "    input = torch.rand(1,32*6*6,8)\n",
    "    layer = CapsLayer()\n",
    "    assert layer(input).shape == (1,10,16)\n",
    "test_for_caps_layer()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1.7 胶囊网络\n",
    "实现了前面必须的几层，相信胶囊网络也是非常好搭了。我们定义的胶囊网络最后输出为10个分类向量"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "metadata": {},
   "outputs": [],
   "source": [
    "class CapsNet(nn.Module):\n",
    "    def __init__(self):\n",
    "        super().__init__()\n",
    "        self.conv_layer = nn.Conv2d(1,256,9)\n",
    "        self.primary_layer = PrimaryCapsuleLayer()\n",
    "        self.caps_layer = CapsLayer(nclasses=10, out_channels_dim=16)\n",
    "        \n",
    "    def forward(self, x):\n",
    "        \"\"\"\n",
    "        Args:\n",
    "            x : Input img, (B, 1, 28, 28)\n",
    "        \n",
    "        Return:\n",
    "            the class capsules, each capsule is a 16 dimension vector\n",
    "        \"\"\"\n",
    "        x = self.conv_layer(x)  # (B, 256, 20, 20)\n",
    "        x = self.primary_layer(x)  # (B, 32*6*6, 8)\n",
    "        x = self.caps_layer(x)  # (B, 10, 16)\n",
    "        return x\n",
    "    \n",
    "def test_for_caps_net():\n",
    "    input = torch.rand(1,1,28,28)\n",
    "    model = CapsNet()\n",
    "    assert model(input).shape == (1,10,16)\n",
    "    \n",
    "test_for_caps_net()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 实验1 训练一个分类的胶囊网络\n",
    "\n",
    "## 实现损失\n",
    "现在我们来到第一个实验，训练一个分类网络。首先了解原文提到的损失\n",
    "\n",
    "$$\n",
    "L_{k}=T_{k} \\max \\left(0, m^{+}-\\left\\|\\mathbf{v}_{k}\\right\\|\\right)^{2}+\\lambda\\left(1-T_{k}\\right) \\max \\left(0,\\left\\|\\mathbf{v}_{k}\\right\\|-m^{-}\\right)^{2}\n",
    "$$\n",
    "\n",
    "这其中$\\left\\|\\mathbf{v}_{k}\\right\\|$就是胶囊网络最后输出来的分类胶囊，k表示第k个。这个式子可以理解为一个分段函数\n",
    "\n",
    "\\begin{equation}\n",
    "L_{k}=\\left\\{\n",
    "\\begin{aligned}\n",
    "\\max \\left(0, m^{+}-\\left\\|\\mathbf{v}_{k}\\right\\|\\right)^{2}& & {第k个胶囊正确分类} \\\\\n",
    "\\lambda \\max \\left(0,\\left\\|\\mathbf{v}_{k}\\right\\|-m^{-}\\right)^{2} & & {第k个胶囊错误分类}\n",
    "\\end{aligned}\n",
    "\\right.\n",
    "\\end{equation}\n",
    "\n",
    "其中$m^{+}=0.9,m^{-}=0.1, \\lambda=0.5$，也就是说，分类胶囊是概率为0.9以上且分类正确的，以及概率为0.1且错误的，我们都是为是”好“的，因此训练时我们采样梯度下降到方式往这个方向靠拢。   \n",
    "因此，我们首先需要自定义一个损失。在pytorch里面，损失定义很简单\n",
    "\n",
    "一些细节\n",
    "- 使用onehot向量T和预测胶囊模长相乘来选取正确预测的值，(1-T)和预测胶囊模长相乘来选取错误预测的值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "metadata": {},
   "outputs": [],
   "source": [
    "#TODO: test it!\n",
    "def margin_loss(y, y_hat):\n",
    "    \"\"\"\n",
    "    Args:\n",
    "        y: ground truth labels (B)\n",
    "        y_hat: class capsules with (B, 10, 16)\n",
    "        \n",
    "    Return\n",
    "        the margin loss\n",
    "    \"\"\"\n",
    "    _lambda = 0.5\n",
    "    m_plus = 0.9\n",
    "    m_minus = 0.1\n",
    "    nclasses = 10\n",
    "    \n",
    "    y_norm = y_hat.norm(dim=-1) # (B,10)\n",
    "    T = F.one_hot(y, nclasses) # use it as index for right class (B,10)\n",
    "    T = T.float()\n",
    "\n",
    "    right = torch.max(torch.zeros_like(y_norm), m_plus-y_norm*T)\n",
    "    right = right**2\n",
    "    wrong = torch.max(torch.zeros_like(y_norm), y_norm*(1-T)-m_minus)\n",
    "    wrong = _lambda*wrong**2\n",
    "    return torch.sum(right+wrong)\n",
    "\n",
    "def test_margin_loss():\n",
    "    y = torch.randint(0,10,(20,))\n",
    "    y_hat = torch.rand(20,10,16)\n",
    "    print(margin_loss(y,y_hat).item())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 259,
   "metadata": {},
   "outputs": [],
   "source": [
    "import time\n",
    "\n",
    "def train(net, epochs, dataloader,reconstruction=False, report=30):\n",
    "    \"\"\" \n",
    "    global variable:\n",
    "        - train_loader\n",
    "    \"\"\"\n",
    "    net.train()\n",
    "\n",
    "    optimizer = torch.optim.Adam(net.parameters())\n",
    "\n",
    "    train_history = []\n",
    "    for epoch in range(epochs):\n",
    "        t0 = time.time()\n",
    "        \n",
    "        epoch_loss = torch.tensor(0.)\n",
    "        for batch, (X_batch, y_batch) in enumerate(dataloader):\n",
    "            X_batch, y_batch = X_batch.to(device), y_batch.to(device)\n",
    "            \n",
    "            if reconstruction:\n",
    "                y_hat_param = net(X_batch, y_batch)\n",
    "                loss = total_loss(X_batch, y_batch, y_hat_param)\n",
    "            else:\n",
    "                y_hat = net(X_batch)\n",
    "                loss = margin_loss(y_batch, y_hat)\n",
    "            epoch_loss += loss\n",
    "\n",
    "            optimizer.zero_grad()\n",
    "            loss.backward()\n",
    "            optimizer.step()\n",
    "\n",
    "        train_history.append(epoch_loss.item())\n",
    "        print(f\"Epoch {epoch+1} loss is {epoch_loss}\")\n",
    "    return train_history"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1\n",
      "\tBatch 459\n",
      "\t\tTraining Loss: 217069.953\n",
      "\t\tTime: 168.944s\n",
      "\tBatch 919\n",
      "\t\tTraining Loss: 215645.812\n",
      "\t\tTime: 168.651s\n",
      "Epoch 2\n",
      "\tBatch 459\n",
      "\t\tTraining Loss: 215400.625\n",
      "\t\tTime: 168.716s\n",
      "\tBatch 919\n",
      "\t\tTraining Loss: 215362.047\n",
      "\t\tTime: 169.112s\n",
      "Epoch 3\n",
      "\tBatch 459\n",
      "\t\tTraining Loss: 215193.094\n",
      "\t\tTime: 167.462s\n",
      "\tBatch 919\n",
      "\t\tTraining Loss: 215290.953\n",
      "\t\tTime: 169.099s\n",
      "Epoch 4\n",
      "\tBatch 459\n",
      "\t\tTraining Loss: 215119.266\n",
      "\t\tTime: 168.276s\n",
      "\tBatch 919\n",
      "\t\tTraining Loss: 215151.844\n",
      "\t\tTime: 171.731s\n",
      "Epoch 5\n",
      "\tBatch 459\n",
      "\t\tTraining Loss: 215083.062\n",
      "\t\tTime: 168.992s\n",
      "\tBatch 919\n",
      "\t\tTraining Loss: 215115.438\n",
      "\t\tTime: 173.077s\n"
     ]
    }
   ],
   "source": [
    "# Start training\n",
    "torch.autograd.set_detect_anomaly(True)\n",
    "\n",
    "encoder = CapsNet().to(device)\n",
    "train(encoder, 5, train_loader, margin_loss, report=460)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Test the model\n",
    "def evaluate(model, test_loader):\n",
    "    model.eval()  # eval mode (batchnorm uses moving mean/variance instead of mini-batch mean/variance)\n",
    "\n",
    "    with torch.no_grad():\n",
    "        correct = 0\n",
    "        total = 0\n",
    "        for images, labels in test_loader:\n",
    "            images = images.to(device)\n",
    "            labels = labels.to(device)\n",
    "            outputs = model(images)\n",
    "            outputs = outputs.norm(dim=-1)\n",
    "            _, predicted = torch.max(outputs.data, 1)\n",
    "            total += labels.size(0)\n",
    "            correct += (predicted == labels).sum().item()\n",
    "    return correct / total\n",
    "\n",
    "acc = evaluate(encoder, test_loader)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 73,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Test Accuracy of the model on the 10000 test images: 98.62%\n"
     ]
    }
   ],
   "source": [
    "print('Test Accuracy of the model on the 10000 test images: {:.2f}%'.format(100 * acc))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "有点惊喜，训练了五个epoch，效果还不错。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 实验2 构建重建网络\n",
    "## 解码器实现\n",
    "除了做简单的分类外，原作者对预测正确的向量进行解码，解码到图片空间。这个过程现有的实现都是用MLP来实现的。也就是说，对一个预测正确的向量(1x16)，使用`(16 --> 28*28)`的解码网络即可，只是中间网络层数可能需要多一些。原文用了三个全连接层，[1][2]给隐层size设定都是512，1024。\n",
    "\n",
    "这里编程的细节有\n",
    "- 运用zip来迭代两个序列\n",
    "- 根据list来选元素: `class_capsules[torch.arange(B), y]`，参考https://discuss.pytorch.org/t/selecting-element-on-dimension-from-list-of-indexes/36319/3\n",
    "- 在训练的时候，因为前面encoder已经训练过了，我们可以冻结掉前面编码网络参数，只训练解码网络，可以进行下列操作\n",
    "\n",
    "\n",
    "```python\n",
    "\n",
    "def set_parameter_requires_grad(model, feature_extracting):\n",
    "    if feature_extracting:\n",
    "        for param in model.parameters():\n",
    "            param.requires_grad = False\n",
    "            \n",
    "set_parameter_requires_grad(encoder, True)\n",
    "# 对优化器\n",
    "optimizer = optim.Adam(\n",
    "        filter(lambda p: p.requires_grad, net.parameters()),\n",
    "        lr=0.1\n",
    "    )\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 253,
   "metadata": {},
   "outputs": [],
   "source": [
    "class MLPDecoder(nn.Module):\n",
    "    \"\"\"Decode the input predicted vectors tor origin images\n",
    "    \n",
    "    Usage:\n",
    "        decoder = MLPDecoder([512, 1024], 16, (28,28))\n",
    "        reconstructed_x = decoder(selected_capsules)\n",
    "    \"\"\"\n",
    "    def __init__(self, hidden, in_channels, out_shape):\n",
    "        super().__init__()\n",
    "        self.out_shape = out_shape\n",
    "        h,w = out_shape\n",
    "        out_channels = w*h\n",
    "        self.mlp = nn.Sequential(*[\n",
    "            nn.Linear(_in, _out)\n",
    "            for _in,_out in zip([in_channels]+hidden, hidden+[out_channels])\n",
    "        ])\n",
    "        \n",
    "        \n",
    "    def forward(self, x):\n",
    "        \"\"\"\n",
    "        Args:\n",
    "            x: (B,16)\n",
    "            \n",
    "        Return:\n",
    "            reconstructed images with (B,1,28,28)\n",
    "        \"\"\"\n",
    "        B = x.shape[0]\n",
    "        x = self.mlp(x)\n",
    "        x = x.reshape(B, 1, *self.out_shape)\n",
    "        return x\n",
    "    \n",
    "def test_decoder():\n",
    "    decoder = MLPDecoder([512, 1024], 16, (28,28))\n",
    "    x = torch.rand(5,16)\n",
    "    assert decoder(x).shape == (5,1,28,28)\n",
    "test_decoder()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "对于自编码器的设计，我们将编解码设得灵活一点，通过构造函数传入"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 254,
   "metadata": {},
   "outputs": [],
   "source": [
    "class CapsAE(nn.Module):\n",
    "    def __init__(self, encoder, decoder):\n",
    "        super().__init__()\n",
    "        self.encoder = encoder\n",
    "        self.decoder = decoder\n",
    "        \n",
    "    def forward(self, x, y):\n",
    "        \"\"\"\n",
    "        Args:\n",
    "            x: (B, C, H, W) (B,1,28,28)\n",
    "            y: (B)\n",
    "            \n",
    "        Return:\n",
    "            reconstructed images with (B,1,28,28)\n",
    "        \"\"\"\n",
    "        B = x.shape[0]\n",
    "        \n",
    "        class_capsules = self.encoder(x)  # (B, 10, 16)\n",
    "        selected_capsules = class_capsules[torch.arange(B), y] #  (B, 16)\n",
    "        assert selected_capsules.shape ==  (B, 16)\n",
    "        \n",
    "        reconstructed_x = self.decoder(selected_capsules)\n",
    "        \n",
    "        \n",
    "        return class_capsules,reconstructed_x"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 加上重建损失的总损失\n",
    "\n",
    "$$\n",
    "L_{total} = L_{margin} + 0.0005 \\times L_{reconstruction}\n",
    "$$\n",
    "其中\n",
    "$$\n",
    " L_{reconstruction} = ||x - \\hat{x} ||^2\n",
    "$$\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 265,
   "metadata": {},
   "outputs": [],
   "source": [
    "def total_loss(x, y, y_hat_params, c=0.0005):\n",
    "    \"\"\" marigin loss + 0.00005reconstruction loss\n",
    "    \n",
    "    Args:\n",
    "        x: (B,C,H,W)\n",
    "        y: (B,)\n",
    "        y_hat_params: a tuple of (class_capsules, reconstructed_x)\n",
    "    \"\"\"\n",
    "    class_capsules, reconstructed_x = y_hat_params\n",
    "    \n",
    "    return margin_loss(y, class_capsules)+c*F.mse_loss(x,reconstructed_x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 266,
   "metadata": {},
   "outputs": [],
   "source": [
    "encoder = CapsNet()\n",
    "decoder = MLPDecoder([512, 1024], 16, (28,28))\n",
    "autoencoder = CapsAE(\n",
    "    encoder = encoder,\n",
    "    decoder = decoder\n",
    ").to(device)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "train_loss = train(autoencoder, 5, train_loader, reconstruction=True, report=460)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 模型评估\n",
    "对自编码器，我们从两个方面来评估：\n",
    "- 编码器的分类能力\n",
    "- 解码器解码效果"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 261,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Test Accuracy of the model on the 10000 test images of encoder in AE: 98.80%\n"
     ]
    }
   ],
   "source": [
    "acc = evaluate(encoder, test_loader)\n",
    "print('Test accuracy of the model on the 10000 test images of encoder in AE: {:.2f}%'.format(100 * acc))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 262,
   "metadata": {},
   "outputs": [],
   "source": [
    "def evaluate_ae(model, test_loader, once=False):\n",
    "    \"\"\" get all reconstruction results\n",
    "    Args:\n",
    "        model: autoencoder\n",
    "        test_loader\n",
    "        \n",
    "    Return:\n",
    "        origin images and reconstructed images (N,1,28,28)\n",
    "    \"\"\"\n",
    "    model.eval()  # eval mode (batchnorm uses moving mean/variance instead of mini-batch mean/variance)\n",
    "\n",
    "    with torch.no_grad():\n",
    "        X_ = [] # reconstructed images\n",
    "        X = [] # origin images\n",
    "        for images, labels in test_loader:\n",
    "            images = images.to(device)\n",
    "            labels = labels.to(device)\n",
    "            _, x_ = model(images, labels)\n",
    "            X_.append(x_)\n",
    "            X.append(images)\n",
    "            \n",
    "            if once:\n",
    "                break\n",
    "            \n",
    "    return torch.cat(X, dim=0),torch.cat(X_, dim=0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 263,
   "metadata": {},
   "outputs": [],
   "source": [
    "X,X_ =  evaluate_ae(autoencoder, test_loader, once=True)\n",
    "X,X_ = X.cpu(),X_.cpu()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 264,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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1/0qHkbLrwH4Hzt5nqIoSrdRMa4oSktc180A+H8C+O8cx/lVx3ESjuP4HMd5EQ/zlVvxl3gowP6e4zhBx3F+FsA3AfzTR///EMBfdRwn+mgz3r+9g8v6ZwD+947jTDmOMwDg/2b9fwkPc4jb3dcKHoq2v+U83BD6v0GzIFwCMPUoZ3tbHMd51XGc1x/lZucBlPAwDWLPPMrp/lMAf+9ResifAfivHcdJPvosTjuO86VHD/+fAPxfHMd55dHGyzOO40xj+89jt/e2bVs/4kMA337U1r8E4Evif78O4N9yHOfnHt3PpIhSt3z9R6kn/wzAf/aoX04D+D8B+F86uKfRR5tGY3jo3OTQpc9LURRlp6gYVxSlLa7r/pd4KHL+Hh6KoyU8TI34jwC83eI5FTwUe1/Dwwjmfwfgb4tc4H8AoPLotX4DD3OUO+V/xENx+hEebjb8fev//w2AX31UQeMftnmdfxcPI7xrAJ617uVfA/gEwKLjOKsdXFPy0XVt4GGqxBoeloLsFv8VgH/PcZwRPNzQ2Qfg6qP3+108jO7Cdd3fwcONl78FYAvAHwBId/B5tKPdvf06gIuPUmb+oM1r/B8evX8GDyuwmMe6rvsugH8LD/vEJoDv4XG0e7vP8n+Hhw7CHQA/eHTf/3MH9+TDwz49D2AdD52Dv9vB8xRFUbqO47o7Xo1VFEVRFEVRFKULaGRcURRFURRFUXqEinFFURRFURRF6REqxhVFURRFURSlR6gYVxRFURRFUZQeoWJcURRFURRFUXqEinFFURRFURRF6REqxhVFURRFURSlR6gYVxRFURRFUZQeoWJcURRFURRFUXqEinFFURRFURRF6REqxhVFURRFURSlR6gYVxRFURRFUZQeoWJcURRFURRFUXqEinFFURRFURRF6REqxhVFURRFURSlR6gYVxRFURRFUZQeoWJcURRFURRFUXqEinFFURRFURRF6REqxhVFURRFURSlR6gYVxRFURRFUZQeoWJcURRFURRFUXqEinFFURRFURRF6REqxhVFURRFURSlR6gYVxRFURRFUZQeoWJcURRFURRFUXqEinFFURRFURRF6REqxhVFURRFURSlR6gYVxRFURRFUZQeoWJcURRFURRFUXqEinFFURRFURRF6REqxhVFURRFURSlR6gYVxRFURRFUZQeoWJcURRFURRFUXqEinFFURRFURRF6REqxhVFURRFURSlR6gYVxRFURRFUZQeoWJcURRFURRFUXqEinFFURRFURRF6REqxhVFURRFURSlR6gYVxRFURRFUZQeoWJcURRFURRFUXqEinFFURRFURRF6REqxhVFURRFURSlR6gYVxRFURRFUZQeoWJcURRFURRFUXqEinFFURRFURRF6REqxhVFURRFURSlR6gYVxRFURRFUZQeoWJcURRFURRFUXqEinFFURRFURRF6REqxhVFURRFURSlR6gYVxRFURRFUZQeoWJcURRFURRFUXqEinFFURRFURRF6REqxhVFURRFURSlR6gYVxRFURRFUZQeoWJcURRFURRFUXqEinFFURRFURRF6REqxhVFURRFURSlRwS2+b/7VK7icOC0+Lu20WNatRGg7STRvrQ92kbbo220PdpG26N2uzO0L22PttH2eLaRRsYVRVEURVEUpUeoGFcURVEURVGUHqFiXFEURVEURVF6hIpxRVEURVEURekRKsYVRVEURVEUpUdsV01F6SH1eh2lUgmNRgMA4LouGo0G6vU6XNdFpVJBvV43jw8EAgiFQvD5fAgEAuZ7X19fr25BURRFURRFaYOK8QNMJpPB+++/j62tLdRqNTQaDeRyOaytrSGfz+PWrVvIZDLm8cPDw3juueeQSCQwOjqKZDKJiYkJnD17Fn6/v3c3oiiKoiiKoniiYvyA4rouisUiHjx4gLW1NVQqFTQaDWxsbGB+fh6bm5v4yU9+gtXVVfOcyclJVKtVDA4OIp/PY2hoCJFIBI1GQ8V4B7ju41KojtOu9O7RRN6/5KexLRRFURTlaaFi/ABy8+ZNXL9+HQsLC/j+97+PTCaDer2ORqOBYrGIbDaLYrGIUqnU9LxcLodr164hHo9jdXUVAwMDqNfrOHPmDKLRKMLhsIpygeu6KBQKqFQquH79Ot59910Eg0GcP38eAwMDGB8fx+joaK8vc99wXRf1eh2FQgE3btzAxsYGlpaWsLS0hGAwiFQqhUgkgkuXLmFqagp9fX0Ih8O9vmxFURSlQ+r1Omq1mkl7lamtxHEchMNhBINBrKysYHZ2Fo7jIBaLoa+vD5FIBOFwGH19fUgkEvD5dLtht1ExfsBwXRdXr17F7//+72NpaQk//vGPkcvlmqKW/NkeVNlsFpcvX4bf78fw8DDi8TjC4TDe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VxRFURRFUZQeoWJcURRFURRFUXqEinFFURRFURRF6REqxhVFURRFURSlR6gYVxRFURRFUZQeoWJcURRFURRFUXqEinFFURRFURRF6REqxhVFURRFURSlR6gYVxRFURRFUZQeoWJcURRFURRFUXqEinFFURRFURRF6REqxhVFURRFURSlR6gYVxRFURRFUZQeoWJcURRFURRFUXqEinFFURRFURRF6REqxhVFURRFURSlR6gYVxRFURRFUZQeoWJcURRFURRFUXqEinFFURRFURRF6REqxhVFURRFURSlR6gYVxRFURRFUZQeoWJcURRFURRFUXqEinFFURRFURRF6REqxhVFURRFURSlR6gYVxRFURRFUZQeoWJcURRFURRFUXqEinFFURRFURRF6REqxhVFURRFURSlR6gYVxRFURRFUZQeoWJcURRFURRFUXqEinFFURRFURRF6REqxhVFURRFURSlR6gYVxRFURRFUZQeoWJcURRFURRFUXqEinFFURRFURRF6REqxhVFURRFURSlR6gYVxRFURRFUZQeoWJcURRFURRFUXqEinFFURRFURRF6REqxhVFURRFURSlR6gYVxRFURRFUZQeEWj3z9XVVRcAXNfd9Rs4joO9vAafb9Pq9Vo93n5Op9fFxw0NDXm+8Pz8/BNttNd73g32e3baDjt5je2eNzEx0fJNc7lcy3bqNq7rel77du9n31+7vreb1yfxeNzzgZubmy07TCef6054Gp9Dp3jdWyqV8ryofD5vLrzVOHMcB47jmL+3+ly9+rO8hk5sTLsxvlMb0+56vP4Xi8U82yibzZoH76Rf9oJu92ubZDLZcT+S19Pu752wk360l/7R6eN2048AoFKpGLvNvmS/Vqv3k2NQ/n0399FJP97veTcUCnlewLVr11q2kdf19GI8djrOOp3bWrXxhQsXPN/g3r17u9ZJrXRJt8ZNt57X6WufOHHCs400Mq4oO+Qgi5vd8DSdRi/2oz17fU+KclSwxxJF59OkExuhY749R23eOmq0jYwD3l5dpx6JfP523kYnr9vqPbbD63U7ea/dGoBO72On97zT69jp9XgZXdKqLXY6wPczGm7/Lt+rk/fdy7Xtt6HrRl/ppI/0ymDv5n1b3Y/db+2263RVrVWbt4vS7bb9OrmX3fA0V592w0EQCN1s+53OS16P30ubdLsf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\n",
      "text/plain": [
       "<Figure size 936x360 with 20 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "fg, axs = plt.subplots(nrows=2, ncols=10, gridspec_kw={'hspace': 0, 'wspace': 0.1}, figsize=(13,5))\n",
    "fg.suptitle('Groundtruths - Reconstructions')\n",
    "\n",
    "for i in range(10):\n",
    "    axs[0, i].imshow(X[i].squeeze(), cmap='binary')\n",
    "    axs[1, i].imshow(X_[i].squeeze(), cmap='binary')\n",
    "    axs[0, i].axis('off')\n",
    "    axs[1, i].axis('off')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 总结\n",
    "- 重建效果 不是特别好，和[1]相比有些糊，但是基本轮廓是重建出来了\n",
    "\n",
    "# 实验3 分类胶囊的每一位代表什么？"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def evaluate_class_capsule(model, x, y, delta=1, dim=0, l=5):\n",
    "    \"\"\" Simply adding class capsules digit from -7 to 7, to \n",
    "    see what happens about reconstruction.\n",
    "    \n",
    "    Args:\n",
    "        model: autoencoder\n",
    "        x: input image (B,1,28,28)\n",
    "        y\n",
    "        dim: which dim you want to research\n",
    "\n",
    "        \n",
    "    Return \n",
    "        [origin image,reconstructed_xs] [(B,1,28,28), ... ,(B,1,28,28)]\n",
    "    \"\"\"\n",
    "    model.eval()\n",
    "    B = x.shape[0]\n",
    "    encoder, decoder = model.encoder, model.decoder\n",
    "    \n",
    "    with torch.no_grad():        \n",
    "        # Auto encoder, but adding class capsules digit from -7 to 7 \n",
    "        class_capsules = encoder(x)  # (B, 10, 16)\n",
    "        selected_capsules = class_capsules[torch.arange(B), y] #  (B, 16)\n",
    "        assert selected_capsules.shape ==  (B, 16)\n",
    "        \n",
    "        index = F.one_hot(torch.ones(1, dtype=torch.long)*dim, num_classes=16)\n",
    "        index = index.float().to(device)\n",
    "        \n",
    "        shifted_capsules = [selected_capsules+i*delta*index for i in range(-l,l+1)]\n",
    "        reconstructed_xs = [decoder(i) for i in shifted_capsules]\n",
    "        \n",
    "    reconstructed_xs.insert(0, x)\n",
    "    return reconstructed_xs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def research_for_class_capsule(N=2, dim=0, delta=0.5):\n",
    "    \"\"\" Simply test N of first batch of test loader for dim \n",
    "    \n",
    "    \"\"\"\n",
    "    for X,y in test_loader:\n",
    "        X,y = X[0:N].to(device),y[0:N].to(device)\n",
    "        result = evaluate_class_capsule(autoencoder, X, y, delta=delta, dim=dim)\n",
    "        break\n",
    "        \n",
    "    fg, axs = plt.subplots(nrows=N, ncols=len(result), gridspec_kw={'hspace': 0, 'wspace': 0.1}, figsize=(13,5))\n",
    "    fg.suptitle(f'research for capsule dim={dim}, delta={delta}')\n",
    "\n",
    "    for i in range(N):\n",
    "        for j in range(len(result)):\n",
    "            axs[i, j].imshow(result[j][i].squeeze().cpu(), cmap='binary')\n",
    "            axs[i, j].axis('off')\n",
    "    plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def research_for_class_capsule_for(i=0,  delta=0.5):\n",
    "    \"\"\" Test class capsule dim usage for i th test image\n",
    "    \n",
    "    \"\"\"\n",
    "    result = []\n",
    "    for X,y in test_loader:\n",
    "        X,y = X[i][None,...].to(device),y[i][None,...].to(device)\n",
    "        for dim in range(16):\n",
    "            result.append(\n",
    "                evaluate_class_capsule(autoencoder, X, y, delta=delta, dim=dim)\n",
    "            )\n",
    "        break\n",
    "        \n",
    "    fg, axs = plt.subplots(nrows=16, ncols=len(result[0]), gridspec_kw={'hspace': 0, 'wspace': 0.1}, figsize=(13,13))\n",
    "    fg.suptitle(f'research for each dim in capsule, delta={delta}')\n",
    "\n",
    "    for i in range(16):\n",
    "        for j in range(len(result[0])):\n",
    "            axs[i, j].imshow(result[i][j].squeeze().cpu(), cmap='binary')\n",
    "            axs[i, j].axis('off')\n",
    "    plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 一大波结果"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for i in range(10):\n",
    "    research_for_class_capsule_for(i, 0.05)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for i in range(10):\n",
    "    research_for_class_capsule_for(i, 0.1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# BUG 记录\n",
    "- `RuntimeError: Input type (torch.cuda.FloatTensor) and weight type (torch.FloatTensor) should be the same`\n",
    "原因：（1）初级胶囊层的32个卷积单元要放在一个nn.ModuleList里（2）动态路由中的b和c需要与输入在同一个cpu或gpu中。\n",
    "\n",
    "- `one of the variables needed for gradient computation has been modified by an inplace operation: [torch.cuda.FloatTensor [1, 10, 1152, 1, 1]], which is output 0 of AddBackward0, is at version 6; expected version 5 instead. Hint: enable anomaly detection to find the operation that failed to compute its gradient, with torch.autograd.set_detect_anomaly(True)` 这个报错说明的问题是一些需要进行梯度计算的参数在计算后发生了更改，比如类似`b[0]=1`这样的inplace操作。发生了这个错误，首先使用`torch.autograd.set_detect_anomaly(True)`看看能不能定位到错误位置。不过我记得修改了什么地方，查明BUG原因：在我实现的动态路由里，不能用`+=`来更新b，具体如下\n",
    "\n",
    "```python\n",
    "# 报错\n",
    "b += torch.mean(torch.matmul(v[:,:,None,None,:], x), dim=0,keepdim=True)\n",
    "\n",
    "# 正常\n",
    "b = b + torch.mean(torch.matmul(v[:,:,None,None,:], x), dim=0,keepdim=True)\n",
    "\n",
    "# 正常\n",
    "b = b + v[:,:,None,None,:].matmul(x).mean(dim=0,keepdim=True)\n",
    "\n",
    "```\n",
    "可能的一点解释就是这样的方法是这种操作让pytorch以为是原位操作，才会报的错\n",
    "\n",
    "- `RuntimeError: Function 'PowBackward0' returned nan values in its 0th output.`\n",
    "\n",
    "\n",
    "# 思考\n",
    "- 训练速度，我实现版本的速度比较慢，比[1]几乎慢6倍，这个问题需要检查下模型，还有较大改进空间\n",
    "\n",
    "# 参考资料\n",
    "[1]  https://github.com/gchochla/capsules-utils    \n",
    "[2] https://github.com/gram-ai/capsule-networks"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
